/* Laboratorio # 2 - Administración de bases de datos
 Jorge Fallas Ramos         402090469
 José Roberto Sánchez       115400070
 Daniel Villalobos Venegas  402110100
 */
package monitorinitdb.Vista;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;

public class VentArchiv extends JFrame implements ActionListener {

    JFileChooser selArchivo;
    ArrayList<JTextField> redos, control, grupos, tamRedos;
    String[] acciones = {"Agregar Redo", "Agregar Control", "Limpiar", "Continuar"};
    static final String strRedos = "Redo", strControl = "Control";
    private static VentArchiv instance;
    JPanel pR, pC;

    public static VentArchiv getInstance() {
        if (instance == null) {
            instance = new VentArchiv();
        }
        return instance;
    }

    int cantRedos, cantControl;

    private VentArchiv() throws HeadlessException {
        redos = new ArrayList<>();
        control = new ArrayList<>();
        grupos = new ArrayList<>();
        tamRedos = new ArrayList<>();
        configInicial();
        configComp();
        cantRedos = 0;
        cantControl = 0;
        configJFileChooser();
    }

    public static void clean() {
        if (instance != null) {
            instance.limpiar();
        }
    }

    private void configInicial() {
        setTitle("Ventana Selecciona Archivos");
        setPreferredSize(new Dimension(750, 450));
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                try {
                    obtRedos();
                    obtControlFiles();
                    setVisible(false);
                    VentConfig.getInstance().mostrar();
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
                }
            }
        });
    }

    private void configJFileChooser() {
        selArchivo = new JFileChooser();
        selArchivo.setDialogType(JFileChooser.SAVE_DIALOG);
        selArchivo.setFileHidingEnabled(true);
        selArchivo.addChoosableFileFilter(new FileNameExtensionFilter("Archivos de configuración de Oracle", "ora"));
        selArchivo.addChoosableFileFilter(new FileNameExtensionFilter("Archivos de datos de Oracle", new String[]{"dbf, log"}));
    }

    private void configComp() {
        pR = new JPanel();
        pR.setLayout(new BoxLayout(pR, BoxLayout.Y_AXIS));
        JScrollPane scr1 = new JScrollPane(pR, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scr1.setAutoscrolls(true);
        scr1.setMaximumSize(new Dimension(150, 150));
        scr1.setPreferredSize(scr1.getMaximumSize());

        JPanel end = new JPanel(new BorderLayout());

        pC = new JPanel();
        pC.setLayout(new BoxLayout(pC, BoxLayout.Y_AXIS));

        JScrollPane scr2 = new JScrollPane(pC, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scr2.setAutoscrolls(true);
        scr2.setMaximumSize(new Dimension(150, 150));
        scr2.setPreferredSize(scr2.getMaximumSize());

        end.add(scr2, BorderLayout.SOUTH);
        end.add(scr1, BorderLayout.NORTH);
        JLabel tex = new JLabel("<html>Redos Files↑<br><br>Control Files↓</html>");
        tex.setHorizontalAlignment(JLabel.CENTER);
        tex.setFont(new Font("Arial", Font.BOLD, 14));
        end.add(tex, BorderLayout.CENTER);
        this.add(end, BorderLayout.CENTER);

        JPanel botones = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        JButton b;
        for (String s : acciones) {
            b = new JButton(s);
            b.setActionCommand(s);
            botones.add(b);
            b.addActionListener(this);
        }
        this.add(botones, BorderLayout.NORTH);
    }

    void limpiar() {
        pR.removeAll();
        pC.removeAll();
        pR.repaint();
        pC.repaint();
        redos.clear();
        control.clear();
        cantControl = 0;
        cantRedos = 0;
    }

    private JPanel genArchiv(String tipo) {
        JPanel l;
        if (tipo.equals(strControl)) {
            l = new JPanel(new FlowLayout());
            l.add(new JLabel(tipo + ":"));
            JTextField f = genTextF(new Dimension(300, 35), tipo);
            l.add(f);
            JButton del = new JButton("Eliminar");
            del.setActionCommand("Eliminar");
            del.setName(f.getName());
            del.addActionListener(this);
            l.add(del);
            del = new JButton("Editar");
            del.setActionCommand("Editar");
            del.setName(f.getName());
            del.addActionListener(this);
            l.add(del);
            l.setName(del.getName());
        } else {
            l = new JPanel(new FlowLayout());
            l.add(new JLabel(tipo + ":"));
            JTextField f = genTextF(new Dimension(200, 35), tipo);
            l.add(f);

            JButton del = new JButton("Eliminar");
            del.setActionCommand("Eliminar");
            del.setName(f.getName());
            del.addActionListener(this);
            l.add(del);

            del = new JButton("Editar");
            del.setActionCommand("Editar");
            del.setName(f.getName());
            del.addActionListener(this);
            l.add(del);
            l.add(new JLabel("#Grupo:"));

            JTextField b = new JTextField();
            b.setPreferredSize(new Dimension(35, 35));
            b.setName(del.getName());
            grupos.add(b);
            l.add(b);
            l.setName(del.getName());

            JTextField m = new JTextField();
            m.setPreferredSize(new Dimension(45, 35));
            m.setName(del.getName());
            tamRedos.add(m);
            l.add(new JLabel("Tamaño del Redo:"));
            l.add(m);
        }
        l.setBorder(BorderFactory.createRaisedBevelBorder());
        return l;
    }

    private JTextField genTextF(Dimension dimP, String tipo) {
        JTextField c = new JTextField();
        c.setPreferredSize(dimP);
        if (tipo.equals(strRedos)) {
            c.setName(tipo + "_" + (cantRedos + 1));
            redos.add(c);
            cantRedos++;
        } else {
            c.setName(tipo + "_" + (cantControl + 1));
            control.add(c);
            cantControl++;
        }
        c.setEditable(false);
        return c;
    }

    private File solicitaArchivo() throws Exception {
        int status = selArchivo.showSaveDialog(null);
        if (status == JFileChooser.APPROVE_OPTION) {
            File f = selArchivo.getSelectedFile();
            if (!f.exists() && funciona(f)) {
                return f;
            } else {
                throw new Exception("Archivo " + f.getName() + " no permitido, ya existe este archivo");
            }
        }
        return null;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        switch (e.getActionCommand()) {
            case "Agregar Redo": {
                try {
                    File f = solicitaArchivo();
                    if (f != null) {
                        JPanel p = genArchiv(strRedos);
                        JTextField c = (JTextField) p.getComponent(1);
                        c.setText(f.getAbsolutePath());
                        pR.add(p);
                    }
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
                }

                getContentPane().revalidate();
            }
            break;
            case "Agregar Control": {
                try {
                    File f = solicitaArchivo();
                    JPanel p = genArchiv(strControl);
                    JTextField c = (JTextField) p.getComponent(1);
                    c.setText(f.getAbsolutePath());
                    pC.add(p);
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
                }
                getContentPane().revalidate();
            }
            break;
            case "Continuar": {
                try {
                    obtRedos();
                    obtControlFiles();
                    setVisible(false);
                    VentConfig.getInstance().mostrar();
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
                }
            }
            break;
            case "Limpiar": {
                limpiar();
                getContentPane().revalidate();
            }
            break;
            case "Eliminar": {
                JButton b = (JButton) e.getSource();
                eliminarOp(b.getName());
                pR.repaint();
                pC.repaint();
            }
            ;
            break;
            case "Editar": {
                try {
                    JButton b = (JButton) e.getSource();
                    EditarF(b.getName());
                    pR.repaint();
                    pC.repaint();
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
                }
            }
            break;
            default:
                throw new UnsupportedOperationException("Not supported yet." + e.getActionCommand()); //To change body of generated methods, choose Tools | Templates.
        }
    }

    public static String getControlFiles() throws Exception {
        if (instance != null) {
            return instance.obtControlFiles();
        }
        return null;
    }

    public void mostrar() {
        pack();
        setLocationRelativeTo(null);
        getContentPane().revalidate();
        setVisible(true);
    }

    public static void main(String[] args) {
        VentArchiv.getInstance().mostrar();
    }

    private boolean funciona(File f) {
        for (JTextField r : redos) {
            if (r.getText().equals(f.getAbsolutePath())) {
                return false;
            }
        }

        for (JTextField r : control) {
            if (r.getText().equals(f.getAbsolutePath())) {
                return false;
            }
        }
        return true;

    }

    private void eliminarOp(String name) {
        if (name.contains(strRedos)) {
            for (int i = 0; i < pR.getComponentCount(); i++) {
                if (pR.getComponents()[i].getName().equals(name)) {
                    pR.remove(i);
                    redos.remove(i);
                    grupos.remove(i);
                    tamRedos.remove(i);
                    break;
                }
            }
        } else {
            for (int i = 0; i < pC.getComponentCount(); i++) {
                if (pC.getComponents()[i].getName().equals(name)) {
                    pC.remove(i);
                    control.remove(i);
                    break;
                }
            }
        }
    }

    private void EditarF(String name) throws Exception {
        File f = solicitaArchivo();
        if (name.contains(strRedos)) {
            for (Component c : pR.getComponents()) {
                if (c.getName().equals(name)) {
                    JPanel p = (JPanel) c;
                    JTextField a = (JTextField) p.getComponent(1);
                    a.setText(f.getAbsolutePath());
                }
            }
        } else {
            for (Component c : pC.getComponents()) {
                if (c.getName().equals(name)) {
                    JPanel p = (JPanel) c;
                    JTextField a = (JTextField) p.getComponent(1);
                    a.setText(f.getAbsolutePath());
                }
            }
        }
    }

    public String obtControlFiles() throws Exception {
        StringBuilder hilera = new StringBuilder();
        if (!control.isEmpty()) {
            hilera.append("(");
            for (Iterator<JTextField> it = control.iterator(); it.hasNext();) {
                JTextField jTextField = it.next();
                hilera.append(jTextField.getText());
                if (it.hasNext()) {
                    hilera.append(", ");
                }
            }
            hilera.append(")");
            return hilera.toString();
        }
        throw new Exception("Debe haber al menos un control file");
    }

    private class redoGrupo {

        StringBuilder archivos;
        String tamanio;
        Integer val;

        redoGrupo(Integer v, String archivo, String tam) {
            archivos = new StringBuilder();
            tamanio = tam;
            archivos.append("'").append(archivo).append("'");
            val = v;
        }

        void concatena(String archivo, String tam) throws Exception {
            if (!tam.equals(tamanio)) {
                throw new Exception("Los tamaños de los redos agrupados deben ser iguales\nRevisar el archivo " + archivo);
            }
            archivos.append(", ").append("'").append(archivo).append("'");
        }

        String obtGrupo() {
            StringBuilder hilera = new StringBuilder();
            hilera.append("(").append(archivos.toString()).append(") ").append("size ").append(tamanio);
            return hilera.toString();
        }
    };

    public static String getRedos() throws Exception {
        if (instance != null) {
            return instance.obtRedos();
        }
        return null;
    }

    public String obtRedos() throws NumberFormatException, Exception {//Lo uso con los redos del build
        StringBuilder hilera = new StringBuilder();
        SortedMap<Integer, redoGrupo> list = new TreeMap<>();
        Integer val;
        redoGrupo r;
        for (int i = 0; i < redos.size(); i++) {
            JTextField t = grupos.get(i);
            JTextField t2 = redos.get(i);
            JTextField t3 = tamRedos.get(i);
            val = Integer.parseInt(t.getText());
            r = list.get(val);
            if (r == null) {
                r = new redoGrupo(val, t2.getText(), t3.getText());
                list.put(val, r);
            } else {
                r.concatena(t2.getText(), t3.getText());
            }
        }

        if (list.size() < 2) {
            throw new Exception("Debe haber minimo, dos redo log files");
        }
        List<redoGrupo> l = new ArrayList<>(list.values());
        for (Iterator<redoGrupo> it = l.iterator(); it.hasNext();) {
            VentArchiv.redoGrupo grupo = it.next();
            hilera.append("group ").append(grupo.val).append(" ").append(grupo.obtGrupo());
            if (it.hasNext()) {
                hilera.append(", ");
            }
        }
        return hilera.toString();
    }
}
